package com.lb.jwitter.action;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import com.lb.jwitter.service.ConditionReport;
import com.lb.jwitter.service.TblQLDTTXADMNhom;
import com.lb.jwitter.service.TblQLDTTXADMNhomService;
import com.lb.jwitter.service.TblQLDTTXADMPhongThi;
import com.lb.jwitter.service.TblQLDTTXADMPhongThiService;
import com.lb.jwitter.service.TblQLDTTXADMTietHoc;
import com.lb.jwitter.service.TblQLDTTXADMTietHocService;
import com.lb.jwitter.service.TblQLDTTXAHocKyTrongNam;
import com.lb.jwitter.service.TblQLDTTXAHocKyTrongNamService;
import com.lb.jwitter.service.TblQLDTTXALichKiemTraGK;
import com.lb.jwitter.service.TblQLDTTXALichKiemTraGKService;
import com.lb.jwitter.service.TblQLDTTXALichThi;
import com.lb.jwitter.service.TblQLDTTXALichThiService;
import com.lb.jwitter.service.TblQLDTTXALichThiTemp;
import com.lb.jwitter.service.TblQLDTTXALichThiTempService;
import com.lb.jwitter.service.TblQLDTTXALopMonHoc;
import com.lb.jwitter.service.TblQLDTTXALopMonHocHocVien;
import com.lb.jwitter.service.TblQLDTTXALopMonHocHocVienService;
import com.lb.jwitter.service.TblQLDTTXALopMonHocService;
import com.lb.jwitter.service.TblQuyenChiTietService;
import com.lb.jwitter.service.TblTaiKhoan;
import com.lb.jwitter.util.ApplicationContextProvider;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;

public class TblQLDTTXAXepLichThiAction {
	private TblTaiKhoan taiKhoanDangNhap; 
	  
	  public TblTaiKhoan getTaiKhoanDangNhap() { 
	      return taiKhoanDangNhap; 
	  } 
	  public void setTaiKhoanDangNhap(TblTaiKhoan taiKhoanDangNhap) { 
	      this.taiKhoanDangNhap = taiKhoanDangNhap; 
	  } 
	  
	  private List<TblQLDTTXADMTietHoc> tblQLDTTXADMTietHocs;
	  public List<TblQLDTTXADMTietHoc> getTblQLDTTXADMTietHocs(){
		  return tblQLDTTXADMTietHocs;
	  }
	  
	  private List<TblQLDTTXADMPhongThi> tblQLDTTXADMPhongThis;
	  public List<TblQLDTTXADMPhongThi> getTblQLDTTXADMPhongThis(){
		  return tblQLDTTXADMPhongThis;
	  }
	  
	  private List<TblQLDTTXALichThiTemp> tblQLDTTXALichThiTemps;
	  public List<TblQLDTTXALichThiTemp> getTblQLDTTXALichThiTemps(){
		  return tblQLDTTXALichThiTemps;
	  }
	  
	  private List<TblQLDTTXAHocKyTrongNam> tblQLDTTXAHocKyTrongNams; 
	    public List<TblQLDTTXAHocKyTrongNam>  getTblQLDTTXAHocKyTrongNams(){ 
	              return tblQLDTTXAHocKyTrongNams; 
	     } 
	  
	  private TblQLDTTXADMTietHocService tblQLDTTXADMTietHocService;
	  private TblQLDTTXADMPhongThiService tblQLDTTXADMPhongThiService;
	  private TblQLDTTXALopMonHocService tblQLDTTXALopMonHocService;
	  private TblQLDTTXALopMonHocHocVienService tblQLDTTXALopMonHocHocVienService;
	  private TblQLDTTXAHocKyTrongNamService tblQLDTTXAHocKyTrongNamService;
	  private TblQLDTTXALichThiTempService tblQLDTTXALichThiTempService;
	  private List<TblQLDTTXADMNhom> tblQLDTTXADMNhoms;
	    public List<TblQLDTTXADMNhom> getTblQLDTTXADMNhoms(){
	    	return tblQLDTTXADMNhoms;    	
	    }
	    
	    private TblQLDTTXADMNhomService tblQLDTTXADMNhomService;
	    
	    private List<TblQLDTTXALopMonHoc> tblQLDTTXALopMonHocs;
	    public List<TblQLDTTXALopMonHoc> getTblQLDTTXALopMonHocs(){
	    	return tblQLDTTXALopMonHocs;    	
	    }
	    
	    //private TblQLDTTXALopMonHocService tblQLDTTXALopMonHocService;
	    
	  
	  private TblQuyenChiTietService tblQuyenChiTietService;
	  
	@Autowired // Injected by Spring 
	ApplicationContextProvider contextProvider; 

	public String form() throws Exception
	{

		Map session = ActionContext.getContext().getSession();
	     taiKhoanDangNhap =  (TblTaiKhoan) session.get("taiKhoan");
	     if( taiKhoanDangNhap == null) return "noprivilege";
	    ApplicationContext context = contextProvider.getApplicationContext(); 
	    
	    tblQuyenChiTietService = (TblQuyenChiTietService) context.getBean("tbl_Quyen_ChiTietClient"); 
	    /*if(!tblQuyenChiTietService.checkRight(taiKhoanDangNhap.getMaNhomQuyen().getId(), "tbl_CanBo", "sua")){ 
	    	
	    	System.out.println("khong co quyen");
	        return "noprivilege"; 
	    }*/           
	    
	    tblQLDTTXADMTietHocService = (TblQLDTTXADMTietHocService) context.getBean("tbl_QLDTTXA_DM_TietHocClient");
	    tblQLDTTXADMPhongThiService = (TblQLDTTXADMPhongThiService) context.getBean("tbl_QLDTTXA_DM_PhongThiClient");
	    tblQLDTTXAHocKyTrongNamService = (TblQLDTTXAHocKyTrongNamService)  context.getBean("tbl_QLDTTXA_HocKyTrongNamClient");
	    
	    tblQLDTTXADMPhongThis = tblQLDTTXADMPhongThiService.findAlltblQLDTTXADMPhongThi(0, 0);
	    tblQLDTTXADMTietHocs = tblQLDTTXADMTietHocService.findAlltblQLDTTXADMTietHoc(0, 0);
	    
	    List<ConditionReport> cons = new ArrayList<ConditionReport>(); 
	    cons.clear();
        {
        	ConditionReport con = new ConditionReport(); 
            con.setCol("thoiGianBatDau");
            con.setValue1("desc");
            con.setOperator("order");
            cons.add(con);
        }
       
        tblQLDTTXAHocKyTrongNams = tblQLDTTXAHocKyTrongNamService.findtblQLDTTXAHocKyTrongNamByCondition(cons, 20, 1);
        


		return Action.SUCCESS;

	}
	
	public String execute() throws Exception
	{
try{
		Map session = ActionContext.getContext().getSession();
	     taiKhoanDangNhap =  (TblTaiKhoan) session.get("taiKhoan");
	     if( taiKhoanDangNhap == null) return "noprivilege";
	    ApplicationContext context = contextProvider.getApplicationContext(); 
	    
	    tblQuyenChiTietService = (TblQuyenChiTietService) context.getBean("tbl_Quyen_ChiTietClient");
	    tblQLDTTXADMTietHocService = (TblQLDTTXADMTietHocService) context.getBean("tbl_QLDTTXA_DM_TietHocClient");
	    tblQLDTTXADMPhongThiService = (TblQLDTTXADMPhongThiService) context.getBean("tbl_QLDTTXA_DM_PhongThiClient");
	    tblQLDTTXALopMonHocService = (TblQLDTTXALopMonHocService) context.getBean("tbl_QLDTTXA_LopMonHocClient");
	    tblQLDTTXALopMonHocHocVienService = (TblQLDTTXALopMonHocHocVienService)  context.getBean("tbl_QLDTTXA_LopMonHoc_HocVienClient");
	    tblQLDTTXAHocKyTrongNamService = (TblQLDTTXAHocKyTrongNamService)  context.getBean("tbl_QLDTTXA_HocKyTrongNamClient");
	    tblQLDTTXADMNhomService = (TblQLDTTXADMNhomService) context.getBean("tbl_QLDTTXA_DM_NhomClient");
	    tblQLDTTXALichThiTempService = (TblQLDTTXALichThiTempService) context.getBean("tbl_QLDTTXA_LichThi_TempClient");
	    
	    if(!tblQuyenChiTietService.checkRight(taiKhoanDangNhap.getMaNhomQuyen().getId(), "tbl_QLDTTXA_LichThi_Temp", "them")){ 
	    	
	    	System.out.println("khong co quyen");
	        return "noprivilege"; 
	    }  
	    
	    tblQLDTTXADMPhongThis = tblQLDTTXADMPhongThiService.findAlltblQLDTTXADMPhongThi(0, 0);
	    tblQLDTTXADMTietHocs = tblQLDTTXADMTietHocService.findAlltblQLDTTXADMTietHoc(0, 0);
	    tblQLDTTXADMNhoms = tblQLDTTXADMNhomService.findAlltblQLDTTXADMNhom(0, 0);
        lopChuaXepLich = "";
        String lopKoThoiGianThi = "";
	    
	    List<ConditionReport> cons = new ArrayList<ConditionReport>(); 
	    cons.clear();
        {
        	ConditionReport con = new ConditionReport(); 
            con.setCol("thoiGianBatDau");
            con.setValue1("desc");
            con.setOperator("order");
            cons.add(con);
        }
       
        tblQLDTTXAHocKyTrongNams = tblQLDTTXAHocKyTrongNamService.findtblQLDTTXAHocKyTrongNamByCondition(cons, 20, 1);
        
        // xoa tat ca ket qua xep lich cu
        cons.clear();
        {
        	ConditionReport con = new ConditionReport(); 
            con.setCol("nguoiTao.id");
            con.setValue1(taiKhoanDangNhap.getId());
            con.setOperator("eq");
            cons.add(con);
        }
        List<TblQLDTTXALichThiTemp> ltTemps = tblQLDTTXALichThiTempService.findtblQLDTTXALichThiTempByCondition(cons, 0, 0);
        if(ltTemps.size() > 0){
	        List<String> ltTempIds = new ArrayList<String>();
	        for(TblQLDTTXALichThiTemp ltTemp : ltTemps){
	        	ltTempIds.add(ltTemp.getId().toString());
	        }
	        tblQLDTTXALichThiTempService.deleteListtblQLDTTXALichThiTemp(ltTempIds);
        }
        
	    DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
	    List<TimeSlot> timeSlots = new ArrayList<TimeSlot>();
	    
	    JSONArray jsonArr = (JSONArray) JSONSerializer.toJSON( this.timeSlots );
	    for(int i = 0; i < jsonArr.size() ; i++){
	    	//System.out.println("JSON obj");
			JSONObject obj = jsonArr.getJSONObject(i);
			String ngayThiStr = obj.getString("ngayThi");
			//System.out.println(ngayThiStr);
			Date dd = df.parse(ngayThiStr); 
            GregorianCalendar c = new GregorianCalendar(); 
            c.setTime(dd);
            XMLGregorianCalendar ngayThi = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
            
            List<TblQLDTTXADMTietHoc> tietHocs = new ArrayList<TblQLDTTXADMTietHoc>();
            JSONArray tietHocIds = obj.getJSONArray("tietHocIds");
            for(int j = 0; j < tietHocIds.size(); j++){
            	JSONObject tietHoc = tietHocIds.getJSONObject(j);
            	tietHocs.add(tblQLDTTXADMTietHocService.gettblQLDTTXADMTietHoc(tietHoc.getLong("tietHocId")));
            }
            //System.out.println("SL tiet hoc " + tietHocs.size());
            List<TblQLDTTXADMPhongThi> phongThis = new ArrayList<TblQLDTTXADMPhongThi>();
            JSONArray phongThiIds = obj.getJSONArray("phongThiIds");
            for(int k = 0; k < phongThiIds.size(); k++){
            	JSONObject phongThi = phongThiIds.getJSONObject(k);
            	phongThis.add(tblQLDTTXADMPhongThiService.gettblQLDTTXADMPhongThi(phongThi.getLong("phongThiId")));
            }
            //System.out.println("SL phong thi " + phongThis.size());
            // tach ra thanh cac timeslot voi cac tiet hoc lien nhau
            Collections.sort(tietHocs, new Comparator<TblQLDTTXADMTietHoc>() {
    	        public int compare(TblQLDTTXADMTietHoc p1, TblQLDTTXADMTietHoc p2) {
    	            return p1.getId().compareTo(p2.getId());
    	        }

    	    });
            int l = 0;
            while(l < tietHocs.size()){
            	List<TblQLDTTXADMTietHoc> tietHocsTemp = new ArrayList<TblQLDTTXADMTietHoc>();
            	int j = 0;
            	for(j = l; j < tietHocs.size(); j++){
            		TblQLDTTXADMTietHoc th = tietHocs.get(j);
            		tietHocsTemp.add(th);
            		// neu tiet 6 va tiet 15
            		if(th.getId().equals(new Long(6)) || th.getId().equals(new Long(15))){
            			break;
            		}
            		
            		// neu tiet tiep theo la tiet lien ke
            		if(j < (tietHocs.size() -1 )){
            			if(!th.getTietKeTiep().getId().equals(tietHocs.get(j+1).getId())){
            				break;
            			}
            		}
            	}
            	l = j + 1;
            	if(tietHocsTemp.size() > 0){
            		TimeSlot timeSlot = new TimeSlot();
            		timeSlot.setNgayThi(ngayThi);
            		timeSlot.setTietHocs(tietHocsTemp);
            		timeSlot.setPhongThis(phongThis);
            		timeSlots.add(timeSlot);  		
            		//System.out.println("Timeslot " + timeSlot.getNgayThi().toString() + " " + timeSlot.getPhongThis().size() + " " + timeSlot.getTietHocs().size() + " " + timeSlot.getThoiGian() + " phut");
            	}
            }
            
	    }
	    
	    //List<ConditionReport> cons = new ArrayList<ConditionReport>(); 
	    cons.clear();
	    { 
            ConditionReport con = new ConditionReport(); 
            con.setCol("hocKyId.id");
            con.setValue1(hocKyId);
            con.setOperator("eq");
            cons.add(con);	

        }
	    
	    List<LopThi> lopThis = new ArrayList<LopThi>();
    	
	    List<TblQLDTTXALopMonHoc> tblQLDTTXALopMonHocTemps = tblQLDTTXALopMonHocService.findtblQLDTTXALopMonHocByCondition(cons, 0, 0);
	    tblQLDTTXALopMonHocs = new ArrayList<TblQLDTTXALopMonHoc>();
	    if(loaiLichThi == 1){
	    	for(TblQLDTTXALopMonHoc lmh : tblQLDTTXALopMonHocTemps){
	    		try{
		    		if(lmh.getThoiGianKiemTraGK() == 0 || lmh.getThoiGianKiemTraGK() == null){
		    			if(lopKoThoiGianThi.isEmpty()){ 
		    				lopKoThoiGianThi = "<div><label>Các lớp chưa có thời gian thi giữa kỳ. Vui lòng bổ sung thông tin.</label></div><div><ul style='padding: 5px 30px;'>";	    			
			    		}
		    			lopKoThoiGianThi += "<li>Lớp " + (lmh.getMaLop() != null ? lmh.getMaLop() : "") + " " +  lmh.getMonHocId().getTen() + "</li>";
		    			
		    		} else {
		    			tblQLDTTXALopMonHocs.add(lmh);
		    		}
	    		} catch(Exception e){
	    			if(lopKoThoiGianThi.isEmpty()){ 
	    				lopKoThoiGianThi = "<div><label>Các lớp chưa có thời gian thi giữa kỳ. Vui lòng bổ sung thông tin.</label></div><div><ul style='padding: 5px 30px;'>";	    			
		    		}
	    			lopKoThoiGianThi += "<li>Lớp " + (lmh.getMaLop() != null ? lmh.getMaLop() : "") + " " +  lmh.getMonHocId().getTen() + "</li>";
	    			
	    		}
	    	}
	    	if(!lopKoThoiGianThi.isEmpty()){ 
	    		lopKoThoiGianThi += "</ul></div>";
		    }
	    } else if(loaiLichThi == 2){
	    	for(TblQLDTTXALopMonHoc lmh : tblQLDTTXALopMonHocTemps){
	    		try{
	    		if(lmh.getThoiGianThi() == 0 || lmh.getThoiGianThi() == null){
	    			if(lopKoThoiGianThi.isEmpty()){ 
	    				lopKoThoiGianThi = "<div><label>Các lớp chưa có thời gian thi. Vui lòng bổ sung thông tin.</label></div><div><ul style='padding: 5px 30px;'>";	    			
		    		}
	    			lopKoThoiGianThi += "<li>Lớp " + (lmh.getMaLop() != null ? lmh.getMaLop() : "") + " " +  lmh.getMonHocId().getTen() + "</li>";
		    	
	    		} else {
	    			tblQLDTTXALopMonHocs.add(lmh);
	    		}
	    		} catch(Exception e){
	    			if(lopKoThoiGianThi.isEmpty()){ 
	    				lopKoThoiGianThi = "<div><label>Các lớp chưa có thời gian thi. Vui lòng bổ sung thông tin.</label></div><div><ul style='padding: 5px 30px;'>";	    			
		    		}
	    			lopKoThoiGianThi += "<li>Lớp " + (lmh.getMaLop() != null ? lmh.getMaLop() : "") + " " +  lmh.getMonHocId().getTen() + "</li>";
		    	
	    		}
	    		
	    	}
	    	if(!lopKoThoiGianThi.isEmpty()){ 
	    		lopKoThoiGianThi += "</ul></div>";
		    }
	    }
	    
	    for(TblQLDTTXALopMonHoc lopMonHoc : tblQLDTTXALopMonHocs){
	    	cons.clear();
	    	{ 
	            ConditionReport con = new ConditionReport(); 
	            con.setCol("lopMonHocId.id");
	            con.setValue1(lopMonHoc.getId());
	            con.setOperator("eq");
	            cons.add(con);	
	        }
    	   { 
    	       ConditionReport con = new ConditionReport(); 
    	       con.setCol("nhomId.ten"); 
    	       con.setValue1("asc"); 
    	       con.setOperator("order"); 
    	       cons.add(con); 
    	   } 
	    	List<TblQLDTTXALopMonHocHocVien> hocViens = tblQLDTTXALopMonHocHocVienService.findtblQLDTTXALopMonHocHocVienByCondition(cons, 0, 0);
	    	
	    	int l = 0;
	    	while(l < hocViens.size()){
            	List<TblQLDTTXALopMonHocHocVien> hocVienLopThi = new ArrayList<TblQLDTTXALopMonHocHocVien>();
            	int j = 0;
            	for(j = l; j < hocViens.size(); j++){
            		TblQLDTTXALopMonHocHocVien hv = hocViens.get(j);
            		hocVienLopThi.add(hv);            		
            		
            		// neu nhom cua hv ke tiep khong giong hv hien tai
            		if(j < (hocViens.size() -1 )){
            			if(!hv.getNhomId().getId().equals(hocViens.get(j+1).getNhomId().getId())){
            				break;
            			}
            		}
            	}
            	l = j + 1;
            	if(hocVienLopThi.size() > 0){	
            		LopThi lopThi = new LopThi();
            		lopThi.setLopMonHoc(lopMonHoc);
            		lopThi.setTo(hocVienLopThi.get(0).getNhomId());
            		lopThi.setHocViens(hocVienLopThi);
            		lopThis.add(lopThi);
            	}
            }
	    	
	    }
	    
	    // sap xep lop thi theo thu tu so luong hv
	    Collections.sort(lopThis, new Comparator<LopThi>() {
	        public int compare(LopThi p1, LopThi p2) {
	            return p2.getSoLuongHV() - p1.getSoLuongHV();
	        }

	    });
	    
	    /*for(LopThi lt : lopThis){
	    	System.out.println("Lop " + lt.getLopMonHoc().getMonHocId().getTen() + " nhom " + lt.getTo().getTen());
	    }*/
	    
	    //System.out.println("");
	    
	    // sap xep timeslot theo thu tu thoi gian lon toi nho
	    Collections.sort(timeSlots, new Comparator<TimeSlot>() {
	        public int compare(TimeSlot p1, TimeSlot p2) {
	            return p2.getThoiGian() - p1.getThoiGian();
	        }

	    });
	    
	    tblQLDTTXALichThiTemps = sapXep(lopThis, timeSlots);
	    
	    for(TblQLDTTXALichThiTemp tblQLDTTXALichThiTemp : tblQLDTTXALichThiTemps ){
	    	tblQLDTTXALichThiTemp.setNguoiTao(taiKhoanDangNhap);
	    	Long newId = tblQLDTTXALichThiTempService.createtblQLDTTXALichThiTemp(tblQLDTTXALichThiTemp);
	    	tblQLDTTXALichThiTemp.setId(newId);
	    }
	    
	    
	    for(LopThi lt : lopThis){
	    	if(!lt.getDaXepLich()){
	    		if(lopChuaXepLich.isEmpty()){ 
	    			lopChuaXepLich = "<div><label>Các lớp chưa xếp được lịch:</label></div><div><ul style='padding: 5px 30px;'>";	    			
	    		}
	    		lopChuaXepLich += "<li>Lớp " + (lt.getLopMonHoc().getMaLop() != null ? lt.getLopMonHoc().getMaLop() : "") + " " + lt.getLopMonHoc().getMonHocId().getTen() + " - tên " + lt.getTo().getTen() + "</li>";
	    	}
	    }
	    if(!lopChuaXepLich.isEmpty()){ 
	    	lopChuaXepLich += "</ul></div><div><label>Giải pháp đề xuất: tăng thêm dữ liệu đầu vào (Ngày thi, phòng thi, giờ thi)</label></div>";
	    }
	    
	    lopChuaXepLich = lopKoThoiGianThi + lopChuaXepLich;

		return Action.SUCCESS;
} catch(Exception e){
	System.out.println("Loi Insert tbl_QLDTTXA_XepLichThi Action"); 
    e.printStackTrace(); 
    return Action.ERROR; 
}

	}

	private int confirmed;
	
	public int getConfirmed() {
		return confirmed;
	}
	public void setConfirmed(int confirmed) {
		this.confirmed = confirmed;
	}
	
	private int maLoi;
	
	public int getMaLoi() {
		return maLoi;
	}
	public void setMaLoi(int maLoi) {
		this.maLoi = maLoi;
	}
	
	private TblQLDTTXALichThiService tblQLDTTXALichThiService;
	private TblQLDTTXALichKiemTraGKService tblQLDTTXALichKiemTraGKService;
	
	public String save() throws Exception
	{
		Map session = ActionContext.getContext().getSession();
	     taiKhoanDangNhap =  (TblTaiKhoan) session.get("taiKhoan");
	     if( taiKhoanDangNhap == null) return "noprivilege";
	    ApplicationContext context = contextProvider.getApplicationContext(); 
	    
	    tblQuyenChiTietService = (TblQuyenChiTietService) context.getBean("tbl_Quyen_ChiTietClient"); 
	    if(!tblQuyenChiTietService.checkRight(taiKhoanDangNhap.getMaNhomQuyen().getId(), "tbl_QLDTTXA_LichThi", "them")){ 
	    	
	    	System.out.println("khong co quyen");
	        return "noprivilege"; 
	    }          
	    tblQLDTTXALichThiService = (TblQLDTTXALichThiService) context.getBean("tbl_QLDTTXA_LichThiClient"); 
	    tblQLDTTXALichKiemTraGKService = (TblQLDTTXALichKiemTraGKService) context.getBean("tbl_QLDTTXA_LichKiemTraGKClient");
	    tblQLDTTXALichThiTempService = (TblQLDTTXALichThiTempService) context.getBean("tbl_QLDTTXA_LichThi_TempClient");
	    
	    List<ConditionReport> cons = new ArrayList<ConditionReport>();
	    {          	
            ConditionReport con = new ConditionReport(); 
            con.setCol("lopId.hocKyId.id");
            con.setValue1(hocKyId);
            con.setOperator("eq");
            cons.add(con);	
        }
	    
	    List<String> oldIs = new ArrayList<String>();
	    if(loaiLichThi == 1){
	    	List<TblQLDTTXALichKiemTraGK> lichThiCus = tblQLDTTXALichKiemTraGKService.findtblQLDTTXALichKiemTraGKByCondition(cons, 0, 0);
	    	if(lichThiCus.size() > 0){
		    	if(confirmed == 1){
			    	for(TblQLDTTXALichKiemTraGK lichThiCu : lichThiCus){
			    		oldIs.add(lichThiCu.getId().toString());
			    	}
			    	tblQLDTTXALichKiemTraGKService.deleteListtblQLDTTXALichKiemTraGK(oldIs);			    	
			    } else {
			    	maLoi = 1;
			    	return Action.SUCCESS;
			    }
	    	}
	    	
	    	cons.clear();
		    {          	
	            ConditionReport con = new ConditionReport(); 
	            con.setCol("lopId.hocKyId.id");
	            con.setValue1(hocKyId);
	            con.setOperator("eq");
	            cons.add(con);	
	        }
		    {          	
	            ConditionReport con = new ConditionReport(); 
	            con.setCol("nguoiTao.id");
	            con.setValue1(taiKhoanDangNhap.getId());
	            con.setOperator("eq");
	            cons.add(con);	
	        }
		    List<TblQLDTTXALichThiTemp> lichThiTemps = tblQLDTTXALichThiTempService.findtblQLDTTXALichThiTempByCondition(cons, 0, 0);
		    for(TblQLDTTXALichThiTemp lichThiTemp : lichThiTemps){
		    	TblQLDTTXALichKiemTraGK lichThiMoi = new TblQLDTTXALichKiemTraGK();
		    	lichThiMoi.setGhiChu(lichThiTemp.getGhiChu());
		    	lichThiMoi.setLopId(lichThiTemp.getLopId());
		    	lichThiMoi.setNgayThi(lichThiTemp.getNgayThi());
		    	lichThiMoi.setNhomId(lichThiTemp.getNhomId());
		    	lichThiMoi.setPhongId(lichThiTemp.getPhongId());
		    	lichThiMoi.setThoiGian(lichThiTemp.getThoiGian());
		    	lichThiMoi.setTietThiId(lichThiTemp.getTietThiId());
		    	
		    	tblQLDTTXALichKiemTraGKService.createtblQLDTTXALichKiemTraGK(lichThiMoi);
		    }
		    
	    } else if(loaiLichThi == 2) {
	    	List<TblQLDTTXALichThi> lichThiCus = tblQLDTTXALichThiService.findtblQLDTTXALichThiByCondition(cons, 0, 0);
	    	if(lichThiCus.size() > 0){
		    	if(confirmed == 1){
			    	for(TblQLDTTXALichThi lichThiCu : lichThiCus){
			    		oldIs.add(lichThiCu.getId().toString());
			    	}
			    	tblQLDTTXALichThiService.deleteListtblQLDTTXALichThi(oldIs);			    	
			    } else {
			    	maLoi = 1;
			    	return Action.SUCCESS;
			    }
	    	}
	    	
	    	cons.clear();
		    {          	
	            ConditionReport con = new ConditionReport(); 
	            con.setCol("lopId.hocKyId.id");
	            con.setValue1(hocKyId);
	            con.setOperator("eq");
	            cons.add(con);	
	        }
		    {          	
	            ConditionReport con = new ConditionReport(); 
	            con.setCol("nguoiTao.id");
	            con.setValue1(taiKhoanDangNhap.getId());
	            con.setOperator("eq");
	            cons.add(con);	
	        }
		    List<TblQLDTTXALichThiTemp> lichThiTemps = tblQLDTTXALichThiTempService.findtblQLDTTXALichThiTempByCondition(cons, 0, 0);
		    for(TblQLDTTXALichThiTemp lichThiTemp : lichThiTemps){
		    	TblQLDTTXALichThi lichThiMoi = new TblQLDTTXALichThi();
		    	lichThiMoi.setGhiChu(lichThiTemp.getGhiChu());
		    	lichThiMoi.setLopId(lichThiTemp.getLopId());
		    	lichThiMoi.setNgayThi(lichThiTemp.getNgayThi());
		    	lichThiMoi.setNhomId(lichThiTemp.getNhomId());
		    	lichThiMoi.setPhongId(lichThiTemp.getPhongId());
		    	lichThiMoi.setThoiGian(lichThiTemp.getThoiGian());
		    	lichThiMoi.setTietThiId(lichThiTemp.getTietThiId());
		    	
		    	tblQLDTTXALichThiService.createtblQLDTTXALichThi(lichThiMoi);
		    }
	    } else {
	    	maLoi = 1;
	    	return Action.ERROR;
	    }
	    
	    

		return Action.SUCCESS;
	}
	
	private int soLuongTietHoc(int thoiGian){
		if(thoiGian % 45 == 0) return thoiGian/45;
		else return thoiGian/45 + 1;
	}
	
	private List<TblQLDTTXALichThiTemp> sapXep(List<LopThi> lopThis, List<TimeSlot> timeSlots){
		List<TblQLDTTXALichThiTemp> lichThis = new ArrayList<TblQLDTTXALichThiTemp>();
		
		boolean[][] adjMtx = new boolean[lopThis.size()][lopThis.size()];
		int i = 0;
		int j = 0;
		
		//initial adj matrix
		for(i=0; i<lopThis.size(); i++){
			for(j=0; j<lopThis.size(); j++){
				adjMtx[i][j] = false;
			}
		}
		
		for(i=0; i<lopThis.size(); i++){
			for(j=0; j<lopThis.size(); j++){
				if(i != j){
					LopThi lopThi1 = lopThis.get(i);
					LopThi lopThi2 = lopThis.get(j);
					
					boolean coHVChung = false;
					for(TblQLDTTXALopMonHocHocVien hvLop1 : lopThi1.getHocViens()){
						for(TblQLDTTXALopMonHocHocVien hvLop2 : lopThi2.getHocViens()){
							if(hvLop1.getHocVienId().getId().equals(hvLop2.getHocVienId().getId())){
								coHVChung = true;
								break;
							}
						}
						if(coHVChung) break;
					}
					
					if(coHVChung){
						adjMtx[i][j] = true;
						adjMtx[j][i] = true;
					}
				} else {
					adjMtx[i][j] = true;
				}
			}
		}
		
		//System.out.println("Adj matrix");
		for(i=0; i<lopThis.size(); i++){
			for(j=0; j<lopThis.size(); j++){
				//System.out.print(adjMtx[i][j] + " ");
			} 
			//System.out.println();
		}
				
		for(i=0; i<lopThis.size(); i++){
		//for(LopThi lopThi : lopThis){
			LopThi lopThi = lopThis.get(i);
			if(!lopThi.getDaXepLich()){
				int thoiGianThi = 0;
				if(loaiLichThi == 1){
					thoiGianThi = lopThi.getLopMonHoc().getThoiGianKiemTraGK();
				} else {
					thoiGianThi = lopThi.getLopMonHoc().getThoiGianThi();
				}
				
				//System.out.println("Lop thi " + lopThi.getLopMonHoc().getMonHocId().getTen() + " nhom " + lopThi.getTo().getTen());
				//System.out.println("Possible timeslot");
				
				
				List<TimeSlot> possibleTimeSlot = new ArrayList<TimeSlot>();
				for(TimeSlot ts : timeSlots){
					if(ts.getThoiGian() >= thoiGianThi){
						possibleTimeSlot.add(ts);
						//System.out.println(ts.getNgayThi().toString() + " " + ts.getPhongThis().size() + " " + ts.getTietHocs().size());
						
					}
				}
				
				if(possibleTimeSlot.size() > 0){
					
					if(possibleTimeSlot.size() > 1){
					// sap xep timeslot theo thu tu thoi gian nho toi lon
					    Collections.sort(possibleTimeSlot, new Comparator<TimeSlot>() {
					        public int compare(TimeSlot p1, TimeSlot p2) {
					            return p1.getThoiGian() - p2.getThoiGian();
					        }
		
					    });
					}
					
					
				    for(TimeSlot ts : possibleTimeSlot){
				    	List<TblQLDTTXADMPhongThi> possiblePhongThi = getPossiblePhongThis(ts, lopThi);
				    	
				    	if(possiblePhongThi.size() > 0){					    				    		
				    		// tim thay timeslot phu hop, sap lich cho lop hien tai
				    		TblQLDTTXADMPhongThi phongThiPhuHop = possiblePhongThi.get(0);
				    		
				    		TblQLDTTXALichThiTemp lichThi = new TblQLDTTXALichThiTemp();
				    		lichThi.setLopId(lopThi.getLopMonHoc());
				    		lichThi.setNgayThi(ts.getNgayThi());
				    		lichThi.setNhomId(lopThi.getTo());
				    		lichThi.setPhongId(phongThiPhuHop);
				    		lichThi.setThoiGian(thoiGianThi);
				    		lichThi.setTietThiId(ts.getTietHocs().get(0));
				    		lichThis.add(lichThi);
				    		lopThi.setDaXepLich(true);
				    		
				    		ts.removePhongThi(phongThiPhuHop);
				    		if(ts.getPhongThis().size() > 0){
					    		if(soLuongTietHoc(thoiGianThi) < ts.getTietHocs().size()){
					    			List<TblQLDTTXADMPhongThi> newPts = new ArrayList<TblQLDTTXADMPhongThi>();
					    			newPts.add(phongThiPhuHop);
					    			
					    			List<TblQLDTTXADMTietHoc> newThs = new ArrayList<TblQLDTTXADMTietHoc>();
					    			for (int k1 = (soLuongTietHoc(thoiGianThi)-1); k1 < ts.getTietHocs().size(); k1++ ){
					    				newThs.add(ts.getTietHocs().get(k1));
					    			}
					    			
					    			TimeSlot newTs = new TimeSlot();
					    			newTs.setNgayThi(ts.getNgayThi());
					    			newTs.setTietHocs(newThs);
					    			newTs.setPhongThis(newPts);
				            		timeSlots.add(newTs);  
					    		}
				    		}
				    		else{
				    			timeSlots.remove(ts);
				    		}
				    		// sap lich cho cac lop khac khong co chung hv voi lop nay
				    		// neu con phong thi 
				    		if(ts.getPhongThis().size() > 0){
					    		for(int k=0; k<lopThis.size(); k++){
					    			if(!adjMtx[i][k] && !lopThis.get(k).getDaXepLich()){
					    				LopThi lpt = lopThis.get(k);
					    				if(loaiLichThi == 1){
					    					thoiGianThi = lpt.getLopMonHoc().getThoiGianKiemTraGK();
					    				} else {
					    					thoiGianThi = lpt.getLopMonHoc().getThoiGianThi();
					    				}
					    				possiblePhongThi = getPossiblePhongThis(ts, lpt);
					    				if(possiblePhongThi.size() > 0){
					    					phongThiPhuHop = possiblePhongThi.get(0);
					    					TblQLDTTXALichThiTemp lt = new TblQLDTTXALichThiTemp();
					    					lt.setLopId(lpt.getLopMonHoc());
					    					lt.setNgayThi(ts.getNgayThi());
					    					lt.setNhomId(lpt.getTo());
					    					lt.setPhongId(phongThiPhuHop);
					    					lt.setThoiGian(thoiGianThi);
					    					lt.setTietThiId(ts.getTietHocs().get(0));
								    		lichThis.add(lt);
								    		lpt.setDaXepLich(true);
								    		
								    		ts.removePhongThi(phongThiPhuHop);
								    		if(ts.getPhongThis().size() > 0){
									    		if(soLuongTietHoc(thoiGianThi) < ts.getTietHocs().size()){
									    			List<TblQLDTTXADMPhongThi> newPts = new ArrayList<TblQLDTTXADMPhongThi>();
									    			newPts.add(phongThiPhuHop);
									    			
									    			List<TblQLDTTXADMTietHoc> newThs = new ArrayList<TblQLDTTXADMTietHoc>();
									    			for (int k1 = (soLuongTietHoc(thoiGianThi)-1); k1 < ts.getTietHocs().size(); k1++ ){
									    				newThs.add(ts.getTietHocs().get(k1));
									    			}
									    			
									    			TimeSlot newTs = new TimeSlot();
									    			newTs.setNgayThi(ts.getNgayThi());
									    			newTs.setTietHocs(newThs);
									    			newTs.setPhongThis(newPts);
								            		timeSlots.add(newTs);  
									    		}
								    		}
								    		else{
								    			timeSlots.remove(ts);
								    		}
					    				} else {
					    					break;
					    				}
					    			}
					    		}
				    		}
				    		break;
				    		
				    	} 
				    	
				    }
				}
				
			}
		}
		
		return lichThis;
	}
	
	public List<TblQLDTTXADMPhongThi> getPossiblePhongThis(TimeSlot ts, LopThi lopThi){
		List<TblQLDTTXADMPhongThi> possiblePhongThi = new ArrayList<TblQLDTTXADMPhongThi>();
    	for(TblQLDTTXADMPhongThi phongThi : ts.getPhongThis()){
    		if(phongThi.getSoLuongHV() >= lopThi.getSoLuongHV()){
    			possiblePhongThi.add(phongThi);
    		}
    	}
    	
    	if(possiblePhongThi.size() > 0){
	    	// sap xep phong thi theo thu tu so luong HV nho toi lon
    		if(possiblePhongThi.size() > 1){
			    Collections.sort(possiblePhongThi, new Comparator<TblQLDTTXADMPhongThi>() {
			        public int compare(TblQLDTTXADMPhongThi p1, TblQLDTTXADMPhongThi p2) {
			            return p1.getSoLuongHV() - p2.getSoLuongHV();
			        }

			    });
    		}
    	}
    	return possiblePhongThi;
	}
	
	private String timeSlots;
	public String getTimeSlots(){
		return timeSlots;
	}
	public void setTimeSlots(String timeSlots){
		this.timeSlots = timeSlots;
	}
	
	private Long hocKyId;
	public Long getHocKyId(){
		return hocKyId;
	}
	public void setHocKyId(Long hocKyId){
		this.hocKyId = hocKyId;
	}
	
	private int loaiLichThi;
	public int getLoaiLichThi(){
		return loaiLichThi;
	}
	public void setLoaiLichThi(int loaiLichThi){
		this.loaiLichThi = loaiLichThi;
	}
	
	private String tuNgay;

	public String getTuNgay() {
		return tuNgay;
	}
	public void setTuNgay(String tuNgay) {
		this.tuNgay = tuNgay;
	}
	
	private String denNgay;

	public String getDenNgay() {
		return denNgay;
	}
	public void setDenNgay(String denNgay) {
		this.denNgay = denNgay;
	}
	private String lopChuaXepLich;

	public String getLopChuaXepLich() {
		return lopChuaXepLich;
	}
	public void setLopChuaXepLich(String lopChuaXepLich) {
		this.lopChuaXepLich = lopChuaXepLich;
	}
	
}

class TimeSlot{
	private XMLGregorianCalendar ngayThi;
	private List<TblQLDTTXADMTietHoc> tietHocs;
	private List<TblQLDTTXADMPhongThi> phongThis;
	private int thoiGian;
	
	public XMLGregorianCalendar getNgayThi(){
		return ngayThi;
	}
	
	public void setNgayThi(XMLGregorianCalendar ngayThi){
		this.ngayThi = ngayThi;
	}
	
	public List<TblQLDTTXADMTietHoc> getTietHocs(){
		return tietHocs;
	}
	
	public void setTietHocs(List<TblQLDTTXADMTietHoc> tietHocs){
		this.tietHocs = new ArrayList(tietHocs);
		this.thoiGian = 45*this.tietHocs.size();
	}
	
	public int getThoiGian(){
		return thoiGian;
	}
	
	public List<TblQLDTTXADMPhongThi> getPhongThis(){
		return phongThis;
	}
	
	public void setPhongThis(List<TblQLDTTXADMPhongThi> phongThis){
		Collections.sort(phongThis, new Comparator<TblQLDTTXADMPhongThi>() {
	        public int compare(TblQLDTTXADMPhongThi p1, TblQLDTTXADMPhongThi p2) {
	            return p1.getSoLuongHV() - p2.getSoLuongHV();
	        }

	    });
		this.phongThis = new ArrayList(phongThis);
	}
	
	public boolean removePhongThi(TblQLDTTXADMPhongThi phongThi){
		return this.phongThis.remove(phongThi);
	}
}

class LopThi{
	private TblQLDTTXALopMonHoc lopMonHoc;
	private TblQLDTTXADMNhom to;
	private List<TblQLDTTXALopMonHocHocVien> hocViens;
	private boolean daXepLich;
	
	public TblQLDTTXALopMonHoc getLopMonHoc(){
		return lopMonHoc;
	}
	
	public void setLopMonHoc(TblQLDTTXALopMonHoc lopMonHoc){
		this.lopMonHoc = lopMonHoc;
	}
	
	public TblQLDTTXADMNhom getTo(){
		return to;
	}
	
	public void setTo(TblQLDTTXADMNhom to){
		this.to = to;
	}
	
	public List<TblQLDTTXALopMonHocHocVien> getHocViens(){
		return hocViens;
	}
	
	public void setHocViens(List<TblQLDTTXALopMonHocHocVien> hocViens){
		this.hocViens = hocViens;
	}	
	
	public int getSoLuongHV(){
		return this.hocViens.size();
	}
	
	public boolean getDaXepLich(){
		return daXepLich;
	}
	
	public void setDaXepLich(boolean daXepLich){
		this.daXepLich = daXepLich;
	}
	
	public LopThi(){
		daXepLich = false;
	}
}
